import { Collider2D, EventTouch, KeyCode, Label, Node, UITransform } from "cc";
import { director, Director, sys, assetManager, EventKeyboard, Sprite, input, Input, Contact2DType } from "cc";
import { log } from "console";
import { data } from "./data";
import { GameRoot } from "./shared/GameRoot";

class GlobalInstance {

    public static readonly Instance: GlobalInstance = new GlobalInstance();
    public gameRoot: GameRoot = null;

    private constructor() {
    }

    enterClassicModeGame() {
        director.loadScene("ClassicModeGame");
    }

    enterArcadeModeGame() {
        director.loadScene("ArcadeModeGame");
    }

    enterGetReady() {
        director.loadScene("GetReady");
    }

    enterHall() {
        director.loadScene("Hall");
    }

    returnHall() {
        director.loadScene("Hall");
    }

    /**
     * 游戏状态重置
     */
    initGame() {
        data.gameStatus = 1
        data.distanceY = 0
        data.score = 0
        data.isContactPipeUp = false
        data.isContactPipeDown = false
        data.dz = 0
    }

    /**
     * 游戏启动前
     * @param node 父节点（游戏模式的画布） 
     */
    startGame(node: Node) {
        // 初始化
        G.initGame()
        // 制作背景 并 播放移动
        G.gameRoot.backgroundAniPlay(node)
        // 制作音效播放器
        G.gameRoot.bgmInit(node)
        // 玩家跳跃监听
        if (sys.isMobile) {
            // 手机监听点击
            input.on(Input.EventType.TOUCH_START, G.playerJumpingByTouch, this)
        } else {
            // 电脑监听空格
            input.on(Input.EventType.KEY_DOWN, G.playerJumpingByKeyboard, this)
        }
    }

    /**
     * 游戏运行时
     * @param player 
     * @param node 
     * @param score 
     */
    gameUpdate(player: Node, node: Node, score: Node, mode: string) {
        // 玩家下落
        if (mode === "classic") {
            if (!G.playerFallDown(player)) {
                // 掉出屏幕返回false 结束游戏
                G.stopGame(node, player)
            }
        }
        if (mode === "arcade") {
            if (!G.playerFallDown2(player)) {
                // 掉出屏幕返回false 结束游戏
                G.stopGame(node, player)
            }
        }
        // 每n帧 创建一个柱子
        if (data.gameStatus == 1 && data.dz++ % data.pipeCreateDz == 0) {
            G.gameRoot.pipeCreate(node)
        }
        // 分数变化
        G.scoreChange(score, node)
    }

    /**
     * 玩家跳跃(键盘)
     * @param event 
     */
    playerJumpingByKeyboard(event: EventKeyboard) {
        if (event.keyCode == KeyCode.SPACE) {
            data.distanceY = data.jumpDistanceY
        }
    }

    /**
     * 玩家跳跃(点击)
     * @param event 
     */
    playerJumpingByTouch(event: EventTouch) {
        data.distanceY = data.jumpDistanceY
    }


    /**
     * 玩家坠落（经典）
     * @param node 
     */
    playerFallDown(node: Node): boolean {
        // 掉出屏幕
        if (node.getWorldPosition().y + node.getComponent(UITransform).contentSize.width / 2 < 0) {
            return false
        }
        if (data.gameStatus == 1) {
            // distanceY + D 越加越大，导致 this.birdVec3.y - distanceY 越减越少
            data.distanceY += data.D
            // 鸟顶到天花板不能再上去了
            data.birdVec3.y = (node.getWorldPosition().y + node.getComponent(UITransform).contentSize.height / 2)
                <= data.screenHeight
                ? (data.birdVec3.y - data.distanceY)
                : (data.birdVec3.y - 0.5)
            // 赋值
            node.setPosition(data.birdVec3.x, data.birdVec3.y)
            // 取到全局 供加分
            data.playerWouldVec = node.getWorldPosition()
        }
        return true
    }

    /**
     * 玩家坠落(街机)
     * @param node 
     */
    playerFallDown2(node: Node): boolean {
        // 掉出屏幕
        if (node.getWorldPosition().y + node.getComponent(UITransform).contentSize.height / 2 < 0) {
            return false
        }
        if (node.getWorldPosition().x + node.getComponent(UITransform).contentSize.width / 2 < 0) {
            return false
        }
        if (data.gameStatus == 1) {

            if (!data.isContactPipeDown) {
                // distanceY + D 越加越大，导致 this.birdVec3.y - distanceY 越减越少
                data.distanceY += data.D
                // 鸟顶到天花板不能再上去了
                data.birdVec3.y = (node.getWorldPosition().y + node.getComponent(UITransform).contentSize.height / 2)
                    <= data.screenHeight
                    ? (data.birdVec3.y - data.distanceY)
                    : (data.birdVec3.y - 0.5)
            }

            // 向上飞 tween(this.bird).to(0.1, {angle: 90}).start()
            if (data.distanceY > data.jumpDistanceY && data.distanceY < 0) {
                node.angle = node.angle <= 5 ? node.angle + (sys.isMobile ? 2 : 1) : 5
            } else {
                // 向下飞
                node.angle = node.angle >= -5 ? node.angle - (sys.isMobile ? 2 : 1) : -5
            }

            // 正面碰撞开始，与柱子一起往后
            if (data.isPlayerBackward) {
                data.birdVec3.x -= data.pipeV
            }

            // 正面碰撞结束，回到初始x轴
            if (!data.isPlayerBackward) {
                data.birdVec3.x = data.birdVec3.x < data.playerInitVec.x ? data.birdVec3.x + 2 : data.playerInitVec.x
            }

            // 上柱子底面碰撞 鸟y轴停滞
            if (data.isContactPipeUp) {
                data.birdVec3.y = data.birdVec3.y <= data.pipeUpYMin ? (data.birdVec3.y - data.distanceY) : data.pipeUpYMin
            }

            // 下柱子顶面碰撞 鸟y轴停滞
            if (data.isContactPipeDown) {
                node.setWorldPosition(data.pipeDownYMaxX, data.pipeDownYMax, 0)
            } else {
                // 赋值
                node.setPosition(data.birdVec3.x, data.birdVec3.y)
            }
            // 取到全局 供加分
            data.playerWouldVec = node.getWorldPosition()
        }
        return true
    }

    /**
     * 柱子移动
     * @param node 
     * @param V 
     */
    pipeMove(pipeArray: Node[], V: number, player: Node, pipeInterval: number) {
        if (data.gameStatus == 1) {
            for (let i = 0, n = pipeArray.length; i < n; i++) {

                let pipeWorldVec3 = pipeArray[i].getWorldPosition()

                // x轴重置 y轴重置
                if (pipeWorldVec3.x < -40) {

                    // 5个间隔(间隔包含柱子宽度) - (pipeWorldVec3.x + 40)误差
                    let x = 5 * pipeInterval - 2 * (pipeWorldVec3.x + 40) - 40
                    let y = (Math.random() * 200 - 100) + (data.screenHeight / 2)

                    pipeArray[i].setWorldPosition(x, y, 0)

                    data.scoreAdded[i] = false

                    return
                } else {
                    pipeWorldVec3.x = pipeWorldVec3.x - V
                }
                // 赋值
                pipeArray[i].setWorldPosition(pipeWorldVec3.x, pipeWorldVec3.y, 0)
                // 加分
                if (!data.scoreAdded[i]
                    && player.getWorldPosition().x > (pipeArray[i].getWorldPosition().x + 40)) {
                    data.scoreAdded[i] = true
                    data.score += 1
                    if (data.score != 0 && data.score % 10 == 0) {
                        G.gameRoot.addScoreBgmPlay()
                    }
                }
            }
        }
    }

    /**
     * 分数变化
     * @param score 
     */
    scoreChange(score: Node, node: Node) {
        score.getChildByName("value").getComponent(Label).string = (String)(data.score)
        // 设置分数永远在最上层
        score.setSiblingIndex(node.children.length - 1)
    }

    /**
     * 停止游戏
     * @param node 
     * @param player 
     */
    stopGame(node: Node, player: Node) {
        // 音效
        if (node.parent.name == "ClassicModeGame") {
            G.gameRoot.gameOverBgm1Play()
        }
        if (node.parent.name == "ArcadeModeGame") {
            G.gameRoot.gameOverBgm2Play()
        }
        // 灰度渲染
        player.getComponent(Sprite).grayscale = true
        // 停止
        G.gameRoot.backgroundAniStop()
        data.gameStatus = 0
        // 结算面板
        setTimeout(() => {
            // 弹出UI
            G.gameRoot.showUIGameOver(node)
            // 展示玩家
            player.getComponent(Sprite).grayscale = false
            player.setSiblingIndex(node.children.length - 1)
            player.setPosition(0, 0)
        }, 500)
    }

}

export const G = GlobalInstance.Instance;
